<template>
  <div class="event-pane">
    <div>
      <el-form>
        <el-form-item label="数据来源">
          <el-radio-group
            v-model="dataSource.type"
            @change="handleDataSourceChange"
          >
            <el-radio-button label="http">HTTP</el-radio-button>
            <el-radio-button label="mqtt">MQTT</el-radio-button>
            <el-radio-button label="websocket">WebSocket</el-radio-button>
          </el-radio-group>
        </el-form-item>

        <template v-if="dataSource.type === 'http'">
          <el-form-item label="请求方法">
            <el-select
              v-model="dataSource.method"
              @change="val => updateField('method', val)"
              placeholder="请选择请求方法"
            >
              <el-option label="GET" value="get" />
              <el-option label="POST" value="post" />
              <el-option label="PUT" value="put" />
              <el-option label="DELETE" value="delete" />
            </el-select>
          </el-form-item>

          <el-form-item label="请求地址">
            <el-input
              v-model="dataSource.url"
              @change="val => updateField('url', val)"
              placeholder="请输入请求地址"
            />
          </el-form-item>

          <el-form-item label="请求参数">
            <el-button type="primary" size="small" @click="showParamDialog">添加参数</el-button>
            <div v-if="dataSource.params && dataSource.params.length > 0" class="param-list">
              <div v-for="(param, index) in dataSource.params" :key="index" class="param-item">
                <span>{{ param.key }}: {{ param.value }}</span>
                <el-button type="text" @click="editParam(index)">编辑</el-button>
                <el-button type="text" @click="removeParam(index)">删除</el-button>
              </div>
            </div>
          </el-form-item>

          <el-form-item label="请求头">
            <el-button type="primary" size="small" @click="showHeaderDialog">添加请求头</el-button>
            <div v-if="dataSource.headers && dataSource.headers.length > 0" class="param-list">
              <div v-for="(header, index) in dataSource.headers" :key="index" class="param-item">
                <span>{{ header.key }}: {{ header.value }}</span>
                <el-button type="text" @click="editHeader(index)">编辑</el-button>
                <el-button type="text" @click="removeHeader(index)">删除</el-button>
              </div>
            </div>
          </el-form-item>
        </template>

        <template v-if="dataSource.type === 'mqtt'">
          <el-form-item label="MQTT地址">
            <el-input
              v-model="dataSource.server"
              @change="val => updateField('server', val)"
              placeholder="请输入MQTT服务器地址"
            />
          </el-form-item>

          <el-form-item label="主题">
            <el-input
              v-model="dataSource.topic"
              @change="val => updateField('topic', val)"
              placeholder="请输入订阅主题"
            />
          </el-form-item>

          <el-form-item label="客户端ID">
            <el-input
              v-model="dataSource.clientId"
              @change="val => updateField('clientId', val)"
              placeholder="请输入客户端ID"
            />
          </el-form-item>
        </template>

        <el-form-item label="是否定时刷新">
          <el-switch
            v-model="dataSource.autoRefresh"
            @change="val => updateField('autoRefresh', val)"
          />
        </el-form-item>

        <template v-if="dataSource.autoRefresh">
          <el-form-item label="刷新频率(秒)">
            <el-input-number
              v-model="dataSource.refreshInterval"
              :min="1"
              :max="3600"
              @change="val => updateField('refreshInterval', val)"
              controls-position="right"
            />
          </el-form-item>
        </template>

        <el-form-item label="超时时间(毫秒)">
          <el-input-number
            v-model="dataSource.timeout"
            :min="0"
            :max="60000"
            @change="val => updateField('timeout', val)"
            controls-position="right"
          />
        </el-form-item>

        <el-form-item label="数据处理脚本">
          <el-input
            v-model="dataSource.dataHandler"
            @change="val => updateField('dataHandler', val)"
            type="textarea"
            :rows="3"
            placeholder="请输入数据处理脚本(可选)"
          />
        </el-form-item>
      </el-form>
    </div>

    <!-- 参数/请求头编辑对话框 -->
    <el-dialog
      v-model="paramDialog.visible"
      :title="paramDialog.title"
      width="500px"
      @close="resetParamDialog"
    >
      <el-form label-position="top">
        <el-form-item label="键">
          <el-input v-model="paramDialog.current.key" placeholder="请输入键名" />
        </el-form-item>
        <el-form-item label="值">
          <el-input v-model="paramDialog.current.value" placeholder="请输入键值" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="paramDialog.visible = false">取消</el-button>
        <el-button type="primary" @click="confirmParam">确定</el-button>
      </template>
    </el-dialog>

    <div class="event-tool-bar">
      <el-button type="primary" :icon="Plus" text @click="addEventBinding">添加绑定</el-button>
    </div>
    <el-scrollbar height="calc(100vh - 208px)">
      <div class="event-binding-list">
        <div class="event-binding-row" v-for="(bind, index) in loadBindings" :key="bind.event">
          <div class="item">
            <span>{{ bind.eventName }} → {{ bind.targetMethodName }}</span>
          </div>
          <div>
            <el-button type="primary" :icon="Edit" text @click.stop="editEventBinding(bind)">编辑</el-button>
            <el-button type="danger" :icon="Delete" text @click.stop="removeEventBinding(index)">移除</el-button>
          </div>
        </div>
      </div>
    </el-scrollbar>

    <!-- 数据绑定对话框 -->
    <el-dialog
      v-model="dialogVisible"
      :title="isEditing ? '编辑数据绑定' : '添加数据绑定'"
      width="800px"
      :close-on-click-modal="false"
      draggable
      @close="resetDialog"
    >
      <el-form label-position="top">
        <el-form-item label="组件字段(多层级请用英文'.'分隔，如:user.name)">
          <el-input
            v-model="bindingForm.componentField"
            placeholder="请输入组件字段"
          />
        </el-form-item>
        <el-form-item label="数据字段(多层级请用英文'.'分隔，如:user.name)">
          <el-input
            v-model="bindingForm.dataField"
            placeholder="请输入组件字段对应的数据字段"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="confirmAddEventBinding"
          :disabled="!isFormValid"
        >
          确定
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { reactive } from 'vue-demi'
import { Check, Delete, Plus, Edit } from '@element-plus/icons-vue'
import { ComponentInstance } from '@/types/visual-app'
import { ComponentLibraryService } from '@/api/visual/componentLibraryApi'

const props = defineProps<{
  type: string,
  component?: ComponentInstance,
  structure: any,
  bindings: any[]
}>()

const emit = defineEmits<{
  (e: 'bindings', bindings: any): void
  (e: 'data-source-change', dataSource: any): void
}>()

// 数据源配置
const dataSource = reactive({
  type: 'http',
  method: 'get',
  url: '',
  params: [],
  headers: [],
  server: '',
  topic: '',
  clientId: '',
  autoRefresh: false,
  refreshInterval: 5,
  timeout: 5000,
  dataHandler: ''
})

// 参数/请求头编辑对话框
const paramDialog = reactive({
  visible: false,
  title: '',
  type: 'param', // 'param' or 'header'
  current: { key: '', value: '' },
  editingIndex: -1
})

const bindingForm = reactive({
  componentField: '',
  dataField: ''
})

// 处理数据源类型变化
const handleDataSourceChange = (val: string) => {
  updateField('type', val)
}

// 显示参数对话框
const showParamDialog = () => {
  paramDialog.visible = true
  paramDialog.title = '添加请求参数'
  paramDialog.type = 'param'
  paramDialog.editingIndex = -1
  paramDialog.current = { key: '', value: '' }
}

// 显示请求头对话框
const showHeaderDialog = () => {
  paramDialog.visible = true
  paramDialog.title = '添加请求头'
  paramDialog.type = 'header'
  paramDialog.editingIndex = -1
  paramDialog.current = { key: '', value: '' }
}

// 编辑参数
const editParam = (index: number) => {
  paramDialog.visible = true
  paramDialog.title = '编辑请求参数'
  paramDialog.type = 'param'
  paramDialog.editingIndex = index
  paramDialog.current = { ...dataSource.params[index] }
}

// 编辑请求头
const editHeader = (index: number) => {
  paramDialog.visible = true
  paramDialog.title = '编辑请求头'
  paramDialog.type = 'header'
  paramDialog.editingIndex = index
  paramDialog.current = { ...dataSource.headers[index] }
}

// 删除参数
const removeParam = (index: number) => {
  dataSource.params.splice(index, 1)
  updateField('params', dataSource.params)
}

// 删除请求头
const removeHeader = (index: number) => {
  dataSource.headers.splice(index, 1)
  updateField('headers', dataSource.headers)
}

// 确认参数/请求头
const confirmParam = () => {
  const item = { ...paramDialog.current }
  
  if (paramDialog.type === 'param') {
    if (paramDialog.editingIndex >= 0) {
      dataSource.params[paramDialog.editingIndex] = item
    } else {
      dataSource.params.push(item)
    }
    updateField('params', dataSource.params)
  } else {
    if (paramDialog.editingIndex >= 0) {
      dataSource.headers[paramDialog.editingIndex] = item
    } else {
      dataSource.headers.push(item)
    }
    updateField('headers', dataSource.headers)
  }
  
  paramDialog.visible = false
}

// 重置参数对话框
const resetParamDialog = () => {
  paramDialog.visible = false
  paramDialog.title = ''
  paramDialog.type = 'param'
  paramDialog.editingIndex = -1
  paramDialog.current = { key: '', value: '' }
}

// 更新字段
const updateField = (field: string, value: any) => {
  dataSource[field] = value
  emit('data-source-change', { ...dataSource })
}

// 以下是原有的事件绑定逻辑（保持不变）
const treeProps = { label: 'label', children: 'children' }
const treeParamProps = { label: 'name', children: 'children' }

const loadBindings = ref<any[]>(Array.isArray(props?.bindings) ? [...props.bindings] : [])
const editingIndex = ref<number | null>(null)
const isEditing = computed(() => editingIndex.value !== null)

const dialogVisible = ref(false)
const newEvent = reactive({
  event: '',
  eventName: '',
  target: '',
  targetMethod: '',
  targetMethodName: '',
  targetType: '',
  methodDefParams: undefined,
  params: [] as Array<{
    source: string,
    target: string,
    pSource: string,
    pTarget: string,
    sourceName: string,
    targetName: string
  }>
})

const fieldMappingDialogVisible = ref(false)
const currentMappingIndex = ref<number | null>(null)
const isEditingMapping = computed(() => currentMappingIndex.value !== null)
const currentMapping = reactive({
  pSource: '',
  source: '',
  sourceName: '',
  pTarget: '',
  target: '',
  targetName: '',
})

const bindTargetEvents = ref<any[]>([])
const bindTargetMethods = ref<any[]>([])

const isFormValid = computed(() => {
  return newEvent.event && newEvent.target && newEvent.targetMethod
})

const lifecycleStages = [
  {
    identifier: 'beforeCreate',
    name: '创建之前',
    outputData: [],
    description: '实例初始化之后，数据观测和事件配置之前调用'
  },
  // ...其他生命周期阶段
]

const groupMethods = [
  {
    identifier: 'fadeLeftAnimationend',
    name: '左侧淡入淡出',
    type: 'group',
    outputData: [],
    description: '左侧淡入淡出'
  },
  // ...其他组方法
]

const groupEvents = [
  {
    identifier: 'fadeInLeftAnimationend',
    name: '左侧淡入结束',
    type: 'group',
    outputData: [],
    description: '左侧淡入结束'
  },
  // ...其他组事件
]

const initComponentEvents = async () => {
  if (props.type == 'page') {
    bindTargetEvents.value = lifecycleStages
  } else if (props.type == 'group') {
    bindTargetEvents.value = groupEvents
  } else if (props.type == 'component' && props.component?.componentId) {
    bindTargetEvents.value = await ComponentLibraryService.getComponentDataModels(props.component?.componentId, 'event')
  } else {
    console.warn("【" + props.type + '】未知.')
  }
}

const getMethods = async (componentId: string) => {
  bindTargetMethods.value = await ComponentLibraryService.getComponentDataModels(componentId, 'method')
  newEvent.targetMethod = ''
  newEvent.targetMethodName = ''
  newEvent.methodDefParams = undefined
  newEvent.targetType = ''
}

const handleBindChange = (data: any, ckecked: boolean, child: any) => {
  if (ckecked) {
    if (data.type === 'component') {
      getMethods(data.componentId)
    } else if (data.type === 'group') {
      bindTargetMethods.value = groupMethods
    }
  }
}

let eventParams: any[] = []
const handleEventChange = (val: string) => {
  const selected = bindTargetEvents.value.find(e => e.identifier === val)
  if (selected) {
    newEvent.eventName = selected.name
    const outputData = typeof selected.outputData === 'string' ? JSON.parse(selected.outputData) : []
    let childrens: any[] = []
    for (var item of outputData) {
      let children = {}
      getChildrens(children, item)
      childrens.push(children)
    }
    eventParams = childrens
  } else {
    eventParams = []
  }
}

let targetMethodParams: any[] = []
const handleTargetMethodChange = (val: string) => {
  const selected = bindTargetMethods.value.find(e => e.identifier === val)
  if (selected) {
    newEvent.targetMethodName = selected.name
    const inputData = typeof selected.inputData === 'string' ? JSON.parse(selected.inputData) : []
    let childrens: any[] = []
    for (var item of inputData) {
      let children = {}
      getChildrens(children, item)
      childrens.push(children)
    }
    targetMethodParams = childrens
    newEvent.methodDefParams = inputData

    if (selected.hasOwnProperty('type')) {
      newEvent.targetType = selected.type
    }
  } else {
    targetMethodParams = []
    newEvent.targetType = ''
    newEvent.methodDefParams = undefined
  }
}

const getChildrens = (children: any, item: any) => {
  children['name'] = item.name
  children['identifier'] = item.identifier
  if (item.dataType.type == 'struct' && item.dataType.specs) {
    let childrens: any[] = []
    for (var spec of item.dataType.specs) {
      let child = {
        pidentifier: children.hasOwnProperty('pidentifier') ? children['pidentifier'] + ',' + item.identifier : item.identifier
      }
      getChildrens(child, spec)
      childrens.push(child)
    }
    children['children'] = childrens
  }
  return children
}

const handleTargetMethodClick = (data: any, ckecked: boolean, child: any) => {
  if (ckecked) {
    if (data.hasOwnProperty('pidentifier')) {
      currentMapping.pTarget = data.pidentifier
    }
    currentMapping.targetName = data.name
  } else {
    currentMapping.pTarget = ''
  }
}

const handleEventSourceClick = (data: any, ckecked: boolean, child: any) => {
  if (ckecked) {
    if (data.hasOwnProperty('pidentifier')) {
      currentMapping.pSource = data.pidentifier
    }
    currentMapping.sourceName = data.name
  } else {
    currentMapping.pSource = ''
  }
}

const addEventBinding = () => {
  editingIndex.value = null
  resetNewEvent()
  dialogVisible.value = true
  initComponentEvents()
}

const editEventBinding = (row: any) => {
  editingIndex.value = loadBindings.value.findIndex(b => b.event === row.event)
  Object.assign(newEvent, JSON.parse(JSON.stringify(row)))
  dialogVisible.value = true
  initComponentEvents()
}

const removeEventBinding = async (index: any) => {
  try {
    await ElMessageBox.confirm('确定要移除该事件绑定吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    loadBindings.value.splice(index, 1)
    ElMessage.success('移除成功')
    emit('bindings', loadBindings.value)
  } catch {
    // 用户取消
  }
}

const confirmAddEventBinding = () => {
  if (!isFormValid.value) return

  const eventBinding = {
    event: newEvent.event,
    eventName: newEvent.eventName,
    target: newEvent.target,
    targetMethod: newEvent.targetMethod,
    targetMethodName: newEvent.targetMethodName,
    methodDefParams: newEvent.methodDefParams,
    targetType: newEvent.targetType,
    params: [...newEvent.params]
  }

  if (isEditing.value) {
    loadBindings.value[editingIndex.value!] = eventBinding
  } else {
    loadBindings.value.push(eventBinding)
  }

  dialogVisible.value = false
  ElMessage.success(isEditing.value ? '更新成功' : '添加成功')

  emit('bindings', loadBindings.value)
}

const openAddFieldMappingDialog = () => {
  currentMappingIndex.value = null
  currentMapping.source = ''
  currentMapping.target = ''
  fieldMappingDialogVisible.value = true
}

const editFieldMapping = (index: number) => {
  currentMappingIndex.value = index
  currentMapping.source = newEvent.params[index].source
  currentMapping.target = newEvent.params[index].target
  currentMapping.pSource = newEvent.params[index].pSource
  currentMapping.pTarget = newEvent.params[index].pTarget
  currentMapping.sourceName = newEvent.params[index].sourceName
  currentMapping.targetName = newEvent.params[index].targetName
  fieldMappingDialogVisible.value = true
}

const removeFieldMapping = (index: number) => {
  newEvent.params.splice(index, 1)
}

const confirmFieldMapping = () => {
  const mapping = {
    source: currentMapping.source,
    target: currentMapping.target,
    pSource: currentMapping.pSource,
    pTarget: currentMapping.pTarget,
    sourceName: currentMapping.sourceName,
    targetName: currentMapping.targetName,
  }

  if (isEditingMapping.value) {
    newEvent.params[currentMappingIndex.value!] = mapping
  } else {
    newEvent.params.push(mapping)
  }
  fieldMappingDialogVisible.value = false
}

const resetDialog = () => {
  editingIndex.value = null
  resetNewEvent()
}

const resetNewEvent = () => {
  newEvent.event = ''
  newEvent.target = ''
  newEvent.targetMethod = ''
  newEvent.params = []
}

watch(() => props?.bindings, (val) => {
  loadBindings.value = Array.isArray(val) ? [...val] : []
}, { immediate: true, deep: true })
</script>

<style scoped>
.event-pane {
  .event-tool-bar {
    height: 35px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    margin-bottom: 5px;
    border-left: 2px solid #5d87ff;
    background: #5d87ff21;
    padding: 0 10px;
  }

  .event-binding-list {
    .event-binding-row {
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 13px;
      background: rgba(0, 0, 0, 0.05);
      padding: 0px 8px 0px 8px;
      margin-bottom: 5px;
      border-radius: 4px;

      .item {
        flex: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
}

.param-list {
  margin-top: 10px;
  border: 1px solid #eee;
  border-radius: 4px;
  padding: 5px;

  .param-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px;
    border-bottom: 1px solid #eee;

    &:last-child {
      border-bottom: none;
    }
  }
}

.mapping-container {
  width: 100%;
  border-radius: 4px;

  .event-binding-list {
    margin-top: 10px;
    max-height: 200px;
    overflow-y: auto;
  }
}
</style>